package avicit.bdp.dds.server.worker.task.sparkflow.utils;

import avicit.bdp.core.http.HttpClientUtil;
import avicit.bdp.core.http.common.HttpConfig;
import avicit.bdp.core.http.exception.HttpProcessException;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;

public class FlowUtils {

    private static final Logger logger = LoggerFactory.getLogger(FlowUtils.class);

    private static final String EXCEPTION_STR = "Exception";
    private static final String ERROR_STR = "error";

    /**
     * start process
     *
     * @param formatJson formatJson
     * @return appid
     */
    public static String startFlow(String formatJson) {
        if (StringUtils.isBlank(formatJson)) {
            return "-1";
        }

        logger.info("接口超时时间1000s");
        logger.info("start flow, format json: \n {}", formatJson);

        try {
            long startTime = System.currentTimeMillis();
            HttpConfig config = HttpConfig.custom().timeout(1000 * 1000).url(FlowApiUtils.getFlowStartUrl()).json(formatJson);
            String doPostResult = HttpClientUtil.post(config);
            logger.info("接口调用耗时:{}ms", System.currentTimeMillis() - startTime);

            logger.info("Return information：{}", doPostResult);
            if (StringUtils.isBlank(doPostResult) || doPostResult.contains(EXCEPTION_STR) || doPostResult.contains(ERROR_STR)) {
                throw new RuntimeException(doPostResult);
            }

            // Convert a json string to a json object
            JSONObject obj = JSONObject.parseObject(doPostResult).getJSONObject("flow");
            String appId = obj.getString("id");
            if (StringUtils.isBlank(appId)) {
                return "-1";
            }
            return appId;
        } catch (Exception e) {
            logger.error("start Flow error: ", e);
            throw new RuntimeException(e);
        }
    }


    public static String stopFlow(String appId) {
        Map<String, String> map = new HashMap<>(2);
        map.put("appID", appId);
        String json = JSON.toJSON(map).toString();
        HttpConfig config = HttpConfig.custom().timeout(5 * 1000).url(FlowApiUtils.getFlowStopUrl()).json(json);
        String result = null;
        try {
            result = HttpClientUtil.post(config);
            if (StringUtils.isNotBlank(result) && !result.contains(EXCEPTION_STR)) {
                logger.warn("Interface return exception");
            } else {
                logger.info("Interface return value: " + result);
            }
        } catch (HttpProcessException e) {
            e.printStackTrace();
        }

        return result;
    }

    /**
     * send post request
     */

    public static ThirdProgressVo getFlowProgress(String appId) {
        ThirdProgressVo jd = null;
        Map<String, Object> map = new HashMap<>(2);
        map.put("appID", appId);
        HttpConfig config = HttpConfig.custom().timeout(10 * 1000).url(FlowApiUtils.getFlowProgressUrl()).map(map);
        String doGet = null;
        try {
            doGet = HttpClientUtil.get(config);
        } catch (HttpProcessException e) {
            e.printStackTrace();
        }
        if (StringUtils.isNotBlank(doGet) && !doGet.contains(EXCEPTION_STR)) {
            String jsonResult = JSONObject.parseObject(doGet).getString("FlowInfo");
            if (StringUtils.isNotBlank(jsonResult)) {
                // Also convert the json string to a json object, and then convert the json object to a java object, as shown below.
                // Convert a json string to a json object
                JSONObject obj = JSONObject.parseObject(jsonResult);
                // Convert a json object to a java object
                jd = JSON.toJavaObject(obj, ThirdProgressVo.class);
                String progressNums = jd.getProgress();
                if (StringUtils.isNotBlank(progressNums)) {
                    try {
                        double progressNumsD = Double.parseDouble(progressNums);
                        jd.setProgress(String.format("%.2f", progressNumsD));
                    } catch (Throwable e) {
                        logger.warn("Progress conversion failed");
                    }
                }
            }
        }
        return jd;
    }

    /**
     * send post request
     */

    public static String getFlowLogUrl(String appId) {
        //ThirdFlowLog thirdFlowLog = null;
        String amContainerLogs = "";

        Map<String, Object> map = new HashMap<>(2);
        map.put("appID", appId);
        HttpConfig config = HttpConfig.custom().timeout(5 * 1000).url(FlowApiUtils.getFlowLogUrl()).map(map);
        String doGet = null;
        try {
            doGet = HttpClientUtil.get(config);
        } catch (HttpProcessException e) {
            e.printStackTrace();
        }

        if (StringUtils.isNotBlank(doGet) && !doGet.contains(EXCEPTION_STR)) {
            logger.info("Successful call : " + doGet);
            // Also convert the json string to a json object, and then convert the json object to a java object, as shown below.
            // Convert a json string to a json object
            JSONObject obj = JSONObject.parseObject(doGet);
            if (null != obj) {
                JSONObject app = obj.getJSONObject("app");
                if (null != app) {
                    amContainerLogs = app.getString("amContainerLogs");
                }
            }
            // Convert a json object to a java object
            // thirdFlowLog = (ThirdFlowLog) JSONObject.toBean(obj, ThirdFlowLog.class);
        } else {
            logger.info("call failed : " + doGet);
        }
        // return thirdFlowLog;
        return amContainerLogs;
    }

    public static String getFlowLogDetail(String appId) {
        Map<String, Object> map = new HashMap<>(2);
        map.put("appID", appId);
        HttpConfig config = HttpConfig.custom().timeout(5 * 1000).url(FlowApiUtils.getFlowLogDetailUrl()).map(map);
        String result = null;
        try {
            result = HttpClientUtil.getAsStringLines(config);
        } catch (HttpProcessException e) {
            e.printStackTrace();
        }
        result = delHtmlTags(result);
        return result;
    }

    public static String getFlowLog(String appId) {
        String content = "";
        Map<String, Object> map = new HashMap<>(2);
        map.put("appID", appId);

        HttpConfig config = HttpConfig.custom().timeout(5 * 1000).url(FlowApiUtils.getFlowLogUrl()).map(map);
        String doGet = null;
        try {
            doGet = HttpClientUtil.get(config);
        } catch (HttpProcessException e) {
            e.printStackTrace();
        }

        if (StringUtils.isNotBlank(doGet) && !doGet.contains(EXCEPTION_STR)) {
            logger.info("Successful call : " + doGet);
            // Also convert the json string to a json object, and then convert the json object to a java object, as shown below.
            // Convert a json string to a json object
            JSONObject obj = JSONObject.parseObject(doGet);
            if (null != obj) {
                JSONObject app = obj.getJSONObject("app");
                if (null != app) {
                    String amContainerLogs = app.getString("amContainerLogs");
                    if (StringUtils.isNotBlank(amContainerLogs)) {
                        //rtnMap.put("stderrLog", amContainerLogs + "/stderr/?start=0");
                        String errUrl = amContainerLogs + "/stderr/?start=0";
                        String outUrl = amContainerLogs + "/stdout/?start=0";
                        content = getSparkLog(errUrl);
                        content = content + "\n\n";
                        content = content + getSparkLog(outUrl);
                    }

                }
            }
            // Convert a json object to a java object
            // thirdFlowLog = (ThirdFlowLog) JSONObject.toBean(obj, ThirdFlowLog.class);
        } else {
            logger.info("call failed : " + doGet);
        }
        // return thirdFlowLog;
        return content;
    }

    public static String getSparkLog(String url) {
        String content = "";
        HttpConfig config = HttpConfig.custom().timeout(5 * 1000).url(url);
        try {
            content = HttpClientUtil.getAsStringLines(config);
            // 使用 jsoup 解析
            Document doc = Jsoup.parse(content);
            Elements e = doc.getElementsByClass(avicit.bdp.dds.common.Constants.CONTENT);
            content = delHtmlTags(e.html());
        } catch (HttpProcessException e) {
            e.printStackTrace();
        }

        return content;
    }


    /**
     * send get
     */

    public static String getCheckpoints(String appId) throws HttpProcessException {
        String jb = null;

        Map<String, Object> map = new HashMap<>(2);
        map.put("appID", appId);
        HttpConfig config = HttpConfig.custom().timeout(5 * 1000).url(FlowApiUtils.getFlowCheckpointsUrl()).map(map);
        String doGet = HttpClientUtil.get(config);

        if (StringUtils.isNotBlank(doGet) && !doGet.contains(EXCEPTION_STR)) {
            // Also convert the json string to a json object, and then convert the json object to a java object, as shown below.
            // Convert a json string to a json object
            JSONObject obj = JSONObject.parseObject(doGet);
            if (null != obj) {
                jb = obj.getString("checkpoints");
            }
        }
        return jb;
    }


    public static String getDebugData(String appID, String stopName, String portName) throws HttpProcessException {
        Map<String, Object> map = new HashMap<>(8);
        map.put("appID", appID);
        map.put("stopName", stopName);
        map.put("port", portName);

        HttpConfig config = HttpConfig.custom().timeout(5 * 1000).url(FlowApiUtils.getFlowDebugDataUrl()).map(map);
        String doGet = HttpClientUtil.get(config);

        logger.info("call succeeded : " + doGet);
//        if (StringUtils.isNotBlank(doGet) && !doGet.contains(EXCEPTION_STR)) {
//            // Also convert the json string to a json object, and then convert the json object to a java object, as shown below.
//            JSONObject obj = JSONObject.fromObject(doGet);// Convert a json string to a json object
//            if (null != obj) {
//                jb = obj.getString("checkpoints");
//            }
//        }
        return doGet;
    }

    public static String getDebugDataAll(String appID, String stopName) throws HttpProcessException {
        Map<String, Object> map = new HashMap<>(8);
        map.put("appID", appID);
        map.put("stopName", stopName);

        HttpConfig config = HttpConfig.custom().timeout(5 * 1000).url(FlowApiUtils.getAllFlowDebugDataUrl()).map(map);
        return HttpClientUtil.get(config);
    }


    public static String getVisualizationData(String appId, String stopName, String visualizationType) throws HttpProcessException {
        Map<String, Object> map = new HashMap<>(8);
        map.put("appID", appId);
        map.put("stopName", stopName);
        map.put("visualizationType", visualizationType);

        HttpConfig config = HttpConfig.custom().timeout(5 * 1000).url(FlowApiUtils.getFlowVisualizationDataUrl()).map(map);
        String doGet = HttpClientUtil.get(config);

        logger.info("call succeeded : " + doGet);
        if (StringUtils.isNotBlank(doGet) && !doGet.contains(EXCEPTION_STR)) {
            return doGet;
        }
        return null;
    }


    /**
     * Send post request
     */
    @SuppressWarnings("rawtypes")
    public static ThirdFlowInfoVo getFlowInfo(String appId) throws HttpProcessException {
        ThirdFlowInfoVo jb = null;
        Map<String, Object> map = new HashMap<>(2);
        map.put("appID", appId);

        HttpConfig config = HttpConfig.custom().timeout(5 * 1000).url(FlowApiUtils.getFlowInfoUrl()).map(map);
        String doGet = HttpClientUtil.get(config);

        if (StringUtils.isNotBlank(doGet) && !doGet.contains(EXCEPTION_STR)) {
            // Also convert the json string to a json object, and then convert the json object to a java object, as shown below.
            // Convert a json string to a json object
            JSONObject obj = JSONObject.parseObject(doGet).getJSONObject("flow");
            // Needed when there is a List in jsonObj
            // Map<String, Class> classMap = new HashMap<String, Class>();
            // Key is the name of the List in jsonObj, and the value is a generic class of list
            // classMap.put("stops", ThirdFlowInfoStopsVo.class);
            // Convert a json object to a java object
            jb = JSON.toJavaObject(obj, ThirdFlowInfoVo.class);
            String progressNums = jb.getProgress();
            if (StringUtils.isNotBlank(progressNums)) {
                try {
                    double progressNumsD = Double.parseDouble(progressNums);
                    jb.setProgress(String.format("%.2f", progressNumsD));
                } catch (Throwable e) {
                    logger.warn("Progress conversion failed");
                }
            }
        }
        return jb;
    }

    private static String delHtmlTags(String htmlStr) {
        //定义script的正则表达式，去除js可以防止注入
        String scriptRegex = "<script[^>]*?>[\\s\\S]*?<\\/script>";
        //定义style的正则表达式，去除style样式，防止css代码过多时只截取到css样式代码
        String styleRegex = "<style[^>]*?>[\\s\\S]*?<\\/style>";
        //定义HTML标签的正则表达式，去除标签，只提取文字内容
        String htmlRegex = "<[^>]+>";
        //定义空格,回车,换行符,制表符
        //String spaceRegex = "\\s*|\t|\r|\n";

        // 过滤script标签
        htmlStr = htmlStr.replaceAll(scriptRegex, "");
        // 过滤style标签
        htmlStr = htmlStr.replaceAll(styleRegex, "");
        // 过滤html标签
        htmlStr = htmlStr.replaceAll(htmlRegex, "");
        // 过滤空格等
        //htmlStr = htmlStr.replaceAll(spaceRegex, "");
        return htmlStr.trim(); // 返回文本字符串
    }

}
